package com.guojian.common.reflect;

import java.io.File;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import javax.persistence.Transient;

import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
import org.springframework.data.util.Streamable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils;

import com.fasterxml.jackson.databind.util.ClassUtil;
import com.google.common.collect.Maps;

public class ReflectUtils extends ReflectionUtils {

	private static final Map<Class<?>, Field[]> DECLARED_FIELDS_CACHE = new ConcurrentReferenceHashMap<>(256);

	private static final Field[] EMPTY_FIELD_ARRAY = new Field[0];

	public static Field[] getDeclaredFields(Class<?> clazz) {
		Assert.notNull(clazz, "Class must not be null");
		Field[] result = DECLARED_FIELDS_CACHE.get(clazz);
		if (result == null) {
			try {
				result = Streamable.of(clazz.getDeclaredFields()).stream().filter(new PredicateFieldImpl()).toArray(Field[]::new);
				DECLARED_FIELDS_CACHE.put(clazz, (result.length == 0 ? EMPTY_FIELD_ARRAY : result));
			} catch (Throwable ex) {
				throw new IllegalStateException("Failed to introspect Class [" + clazz.getName() + "] from ClassLoader [" + clazz.getClassLoader() + "]", ex);
			}
		}
		return result;
	}

	static class PredicateFieldImpl implements Predicate<Field> {

		@Override
		public boolean test(Field field) {

			if (field.getAnnotation(Transient.class) != null) {
				return false;
			}

			if (!ClassUtils.isSimpleType(field.getType())) {
				return false;
			}

			return true;
		}

	}

	static class TestBean {
		private String name;
		private Integer uid;
		private User user;
		private List<String> ls;
		private int b;
		private byte[] c;
		private byte cc;
		private float bb;

		public byte[] getC() {
			return c;
		}

		public void setC(byte[] c) {
			this.c = c;
		}

		public byte getCc() {
			return cc;
		}

		public void setCc(byte cc) {
			this.cc = cc;
		}

		public float getBb() {
			return bb;
		}

		public void setBb(float bb) {
			this.bb = bb;
		}

		public User getUser() {
			return user;
		}

		public void setUser(User user) {
			this.user = user;
		}

		public int getB() {
			return b;
		}

		public void setB(int b) {
			this.b = b;
		}

		private Map<String, Object> map;

		public List<String> getLs() {
			return ls;
		}

		public void setLs(List<String> ls) {
			this.ls = ls;
		}

		public Map<String, Object> getMap() {
			return map;
		}

		public void setMap(Map<String, Object> map) {
			this.map = map;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public Integer getUid() {
			return uid;
		}

		public void setUid(Integer uid) {
			this.uid = uid;
		}

	}

	public static void main(String[] args) {
		
		
		File file = new File("");
		
		
		Object a1 = Maps.newConcurrentMap();

		Object a2 = "1213";

		Object a3 = new Integer(1);

		int aa = 1;
		Object a4 = aa;

		byte[] aaa = new byte[0];
		Object a5 = aaa;

		System.out.println(a1.getClass());
		System.out.println(a2.getClass());
		System.out.println(a3.getClass());
		System.out.println(a4.getClass());
		System.out.println(a5.getClass());

		System.out.println(ClassUtil.isCollectionMapOrArray(a5.getClass()));

		Field[] fields = getDeclaredFields(TestBean.class);

		for (Field field : fields) {
			System.out.println(field.getType() + "===" + field.getGenericType() + "::" + ClassUtils.isSimpleType(field.getType()));
		}

	}

}
